/*
 * Copyright © 2004-2014 chenYuan. All rights reserved.
 * @Website:wwww.jspx.net
 * @Mail:39793751@qq.com
 * @author: chenYuan , 陈原
 * @License: Jspx.net Framework Code is open source (LGPL)，Jspx.net Framework 使用LGPL 开源授权协议发布。
 * @jvm:jdk1.6+  x86/amd64
 *
 */
package com.jspx.sober;

import com.jspx.sober.annotation.*;
import com.jspx.utils.StringUtil;
import com.jspx.utils.ClassUtil;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Created by IntelliJ IDEA.
 * User: chenYuan
 * Date: 2008-8-2
 * Time: 12:16:45
 * com.jspx.sober.AnnoDAOProxy
 *
    <bean id="anonDemoDAO" class="com.jspx.example.AnonDemoDAOImpl" singleton="true">
          <ref name="soberFactory">jspxSoberFactory</ref>
    </bean>

    <bean name="com.jspx.example.dao.AnonDemoDAO" class="com.jspx.sober.AnnoDAOProxy" create="proxy" singleton="false">
       <ref name="target">anonDemoDAO</ref>
    </bean>
  */

public class AnnoDAOProxy implements InvocationHandler
{
    public AnnoDAOProxy()
    {

    }

    private Object target;

    public Object getTarget()
    {
        return target;
    }

    public void setTarget(Object target)
    {
        this.target = target;
    }

    public void setTarget(String target) throws Exception
    {
        this.target = ClassUtil.newInstance(target);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
        method = ClassUtil.getDeclaredMethod(target.getClass(),method.getName(),args.length);
        boolean doTransaction = false;
        Transaction transaction = null;
        SoberSupport soberSupport = (SoberSupport) target;
        Object result;
        Rollback tran = method.getAnnotation(Rollback.class);
        if (tran != null)
        {
            doTransaction = tran.run();
            if (doTransaction)
            {
                transaction = soberSupport.createTransaction();
                transaction.begin();
            }
        }
        try
        {
            Query query = method.getAnnotation(Query.class);
            if (query != null)
            {

                int icount = soberSupport.getMaxRows();
                int ipage = 1;
                if (args.length == 3)
                {
                    icount = StringUtil.toInt(args[args.length - 1].toString());
                    ipage = StringUtil.toInt(args[args.length - 2].toString());
                }
                if (StringUtil.hasLength(query.sql()))
                {
                    if (query.entity().equals(NullClass.class))
                        return soberSupport.queryForList(query.sql(),(Object[])args[0], ipage, icount);
                    else
                        return soberSupport.queryForList(query.entity(),query.sql(), (Object[])args[0], ipage, icount,query.loadChild());
                } else if (StringUtil.hasLength(query.id()) &&!StringUtil.hasLength(query.namespace()))
                {
                    SqlMapClient sqlMapClient = soberSupport.buildSqlMap();
                    return sqlMapClient.queryForList(query.namespace(), query.id(), args[0], ipage, icount, query.loadChild(), query.rollRows());
                }
            }
            UniqueResult uniqueResult = method.getAnnotation(UniqueResult.class);
            if (uniqueResult != null)
            {
                if (!StringUtil.isNULL(query.sql()))
                {
                     if (uniqueResult.entity().equals(NullClass.class))
                        return soberSupport.getUniqueResult(query.sql(), args[0]);
                    else
                       return soberSupport.getUniqueResult(uniqueResult.entity(),query.sql(), args[0]);
                } else if (StringUtil.hasLength(uniqueResult.id()) &&StringUtil.hasLength(uniqueResult.namespace()))
                {
                    SqlMapClient sqlMapClient = soberSupport.buildSqlMap();
                    return sqlMapClient.getUniqueResult(uniqueResult.namespace(), uniqueResult.id(), args[0]);
                }
            }

            Update update = method.getAnnotation(Update.class);
            if (update != null)
            {
                if (StringUtil.hasLength(update.sql()))
                {
                     if (update.entity().equals(NullClass.class))
                        return soberSupport.update(update.sql(), (Object[])args[0]);
                    else
                        return soberSupport.update(update.entity(),update.sql(), args[0]);
                }
                else if (StringUtil.hasLength(update.id()) && StringUtil.hasLength(update.namespace()))
                {
                    SqlMapClient sqlMapClient = soberSupport.buildSqlMap();
                    return sqlMapClient.update(query.namespace(), update.id(), args[0]);
                }
            }

            Execute execute = method.getAnnotation(Execute.class);
            if (execute != null)
            {
                if (!StringUtil.isNULL(update.sql()))
                {
                     if (execute.entity().equals(NullClass.class))
                         return soberSupport.execute(execute.sql(),(Object[])args[0]);
                    else
                         return soberSupport.execute(execute.entity(),execute.sql(),args[0]);
                } else if (StringUtil.hasLength(query.id()) && StringUtil.hasLength(query.namespace()))
                {
                    SqlMapClient sqlMapClient = soberSupport.buildSqlMap();
                    return sqlMapClient.execute(query.namespace(), update.id(), args[0]);
                }
            }
            ////////////////
            result = method.invoke(target, args);
        } catch (Exception e)
        {
            if (doTransaction)
            {
                transaction.rollback();
            }
            e.printStackTrace();
            return -2;
        }
        finally
        {
            if (doTransaction)
            {
                transaction.commit();
            }
        }
        return result;
    }

    public Object getProxy()
    {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), new Class[]{target.getClass().getInterfaces()[0]}, this);
    }

}